// ==============================================================================
//
// software development kit v 3.0
// shared structures unit
//
// copyright (c) 2008-2009 gear pair games
//
// copyright and license exceptions noted in source
//
// description: this struct(s) unit, .
// ==============================================================================
unit GL1Api;

interface

uses
  xml,
  types,
  cls,
  headers,
  math,
  structs,
  enums,
  glx;

const
  // std::apiPreSet
  apiPreSet : structGLApi = ( names : (
      // name-list function
      // get
     'wglGetProcAddress', 'glGetError', 'glGetString', 'glGetIntegerv', 'glGetIntegerv',
      // set
     'glEnable', 'glDisable', 'glViewport', 'glLightfv', 'wglSwapIntervalEXT', 'wglGetSwapIntervalEXT',
      // matrix
     'glMatrixMode', 'glLoadMatrixf',
      // draw
     'glClear', 'glBegin', 'glEnd',
      // vertex
     'glVertex2fv', 'glVertex3fv', 'glVertexPointer',
     // normal
     'glNormal3fv', 'glNormalPointer',
      // color
     'glColor3fv',
      // end name-list
     '#', '#', '#', '#' ) );

threadvar apiGl1 : pStructGLApi;

type

// CGLThread = class
  CGLThread = class( CThread )
  public
    procedure doExecute; override;
  end;

// CGL1Api
  CGL1Api = class( IApiGL1 )
  private
    fThread : CGLThread;
    fApi : CGLCore;
    fMatrixes : array [ camModelView .. camProjView ] of pmat4;
    fXml : CXML;
    fRndIntf : IRenderableApi;
    fTask : listStack;
  private
// CGL1Api::processtask
    procedure processtask( const indx : int );
  public
// CGL1Api::Create
    constructor Create;
// CGL1Api::drawRun
    procedure drawRun;
// CGL1Api::drawEnd
    procedure drawEnd;
// CGL1Api::initThread
    procedure initThread;
  public
// interface
// CGL1Api::doInit
    procedure doInit; override;
// CObject::Cmain::doFree
    procedure doFree; override;
// CGL1Api::doMessage
    procedure doMessage( var inMsg : structMsg ); override;
// CGL1Api::writeStatus
    procedure writeInitStatus; override;
// CGL1Api::initRender
    function initRender( const inXml : CXML; const inIntf : IRenderableApi ) : bool; override;
// CGL1Api::initRender
    procedure freeRender; override;
// CGL1Api::drawCustom
    procedure drawCustom( const intype : enumDrawType; const inData : void ); override;
// CGL1Api::setMatrix
    procedure setMatrix( const intype : enumCamMat; const inData : pmat4 ); override;
// CGL1Api::unsetMatrix
    procedure unsetMatrix( const intype : enumCamMat; const inData : pmat4 ); override;
// CGL1Api::setView
    procedure setView( const inW, inH : int ); override;
  end;

implementation

uses
  os,
  draw,
  consts,
  utils,
  msg;

{ CrenderableApi }

// CGL1Api::create
constructor CGL1Api.Create;
begin
  inherited;
end;

// CGL1Api::doFree
procedure CGL1Api.doFree;
begin
// wait of end thread loop
  fThread.waitAndExit;
// free stack list
  fTask.free( true );
  inherited;
end;

// CGL1Api::doInit
procedure CGL1Api.doInit;
begin
// init fill null
  fillChar( fMatrixes, sizeof( fMatrixes ), 0 );
  // init stack list
  fTask := listStack.Create( 100, sizeof( structApiTask ) );
  fTask.allocAll;
  inherited;
end;

// CGL1Api::doMessage
procedure CGL1Api.doMessage( var inMsg : structMsg );
begin
// update childs
  inherited;
end;

// CGL1Api::initThread
procedure CGL1Api.initThread;
begin
// get pre set
  apiGl1 := @apiPreSet;
// get handle opengl.lib
  fApi := CGLCore.Create( osLibLoad( libGL32 ) );
// init pixel fmt
  fApi.initPixelFormat( fRndIntf.wndHandle );
// init gl functional by gl pre set
  exception( fApi.initGlFunctional( apiGl1^, Self ), msgErrApiGlFunc );
// swap backbuffer-frontbuffer
  fApi.swap;
// turn
// todo: need read in xml params vsync
  apiGl1.&set.vsync.turn( oneInt );
  printf( logDebug, ' VSync:' + intStr( apiGl1.&set.vsync.get ) );
  assert( apiGl1.get.error = 0, 'err' );
// todo: need insert code::check gl error!
end;

// CGL1Api::initRender
function CGL1Api.initRender( const inXml : CXML; const inIntf : IRenderableApi ) : bool;
begin
// off
  apiGl1 := nil;
  fXml := fXml;
  fRndIntf := inIntf;
// create gl thread
  fThread := CGLThread.Create( thrdNormal, Self );
  result := true; // init - complate
end;

// CGL1Api::setMatrix
procedure CGL1Api.setMatrix( const intype : enumCamMat; const inData : pmat4 );
begin
// set matrix data
  fMatrixes[ intype ] := inData;
end;

// CGL1Api::setView
procedure CGL1Api.setView( const inW, inH : int );
const
{$j+}
  taskSetView : structApiTask = ( apifunc : apifnSetView; view : ( x : 0; y : 0 ) );
{$j-}
begin
  taskSetView.view.pos.width := inW;
  taskSetView.view.pos.width := inH;
  fTask.add( @taskSetView );
end;

// CGL1Api::writeInitStatus
procedure CGL1Api.unsetMatrix( const intype : enumCamMat; const inData : pmat4 );
begin
  // todo: cmp void
  fMatrixes[ intype ] := nil;
end;

// CGL1Api::writeInitStatus
procedure CGL1Api.writeInitStatus;
const
  msgErrCnt : ansiString = 'failed to create an opengl rendering context';
  msgDone : ansiString = 'render initialization : done';
begin
// if all test = pass true then done
  printf( logHint, msgDone );
end;

// CGL1Api::drawRun
procedure CGL1Api.drawRun;
var
  i : int;
begin
// read and excure task
  for i := 0 to fTask.count - 1 do
    processtask( i );

  assert( apiGl1.get.error = 0, 'err' );
// clear frame
  apiGl1.draw.clear( glBuffDepthBit or glBuffColorBit );
// set proj view matrix
  apiGl1.matrix.mode( glProjViewMode );
  if fMatrixes[ camProjView ] <> nil then
    apiGl1.matrix.load( fMatrixes[ camProjView ] );
// set model view matrix
  apiGl1.matrix.mode( glModelViewMode );
  if fMatrixes[ camModelView ] <> nil then
    apiGl1.matrix.load( fMatrixes[ camModelView ] );
// error
  assert( apiGl1.get.error = 0, 'err' );
end;

// CGL1Api::exeTask
procedure CGL1Api.processtask( const indx : int );
var
  task : pStructApiTask;
begin
  exit;
// tesk
  task := pStructApiTask( fTask[ indx ] );
// api parese task
  with task^ do
    case apifunc of
// apifnSetRndBuffer
     apifnSetRndBuffer :
     ;
     else
     fApi.processcmd( task, apiGl1 );
     end;
end;

// CGL1Api::drawCustom
procedure CGL1Api.freeRender;
begin
  // free render
  if ( fApi <> nil ) then
    fApi.freeRender;
end;

// CGL1Api::drawCustom
procedure CGL1Api.drawCustom( const intype : enumDrawType; const inData : void );
const
  axisX : vec3 = ( r : 1.0; g : 0.0; b : 0.0 );
  axisY : vec3 = ( x : 0.0; y : 1.0; z : 0.0 );
  axisZ : vec3 = ( x : 0.0; y : 0.0; z : 1.0 );
  posL : vec4 = ( x : 0.0; y : 0.0; z : 1.0; w : 1.0 );
var
  i : int;
  tmp : vec3;
begin
  // on paint gl
  case intype of
///
    drwVertexes :
     begin
     apiGl1.&set.enable( $0b50 );
     apiGl1.&set.disable( $0b44 );
     apiGl1.&set.enable( $0b57 );
     apiGl1.&set.enable( $4000 );
     apiGl1.&set.enable( $0b71 );
     apiGl1.&set.light.params( $4000, $1203, @posL );

     apiGl1.color.c3fv( @nullvec3 );

     apiGl1.draw.&on( gltris );
     for i := 0 to drawMesh( inData^ ).cntF do
     begin
     apiGl1.vertex.v3fv( @drawMesh( inData^ ).verts[ drawMesh( inData^ ).faces[ i ].x ] );
     apiGl1.vertex.v3fv( @drawMesh( inData^ ).verts[ drawMesh( inData^ ).faces[ i ].y ] );
     apiGl1.vertex.v3fv( @drawMesh( inData^ ).verts[ drawMesh( inData^ ).faces[ i ].z ] );
// ver
     apiGl1.normal.n3fv( @drawMesh( inData^ ).norm[ drawMesh( inData^ ).faces[ i ].x ] );
     apiGl1.normal.n3fv( @drawMesh( inData^ ).norm[ drawMesh( inData^ ).faces[ i ].y ] );
     apiGl1.normal.n3fv( @drawMesh( inData^ ).norm[ drawMesh( inData^ ).faces[ i ].z ] );
     end;
     apiGl1.draw.off;
     // disable
     apiGl1.&set.disable( $0b50 );
// draw
     apiGl1.draw.&on( gllines );
     apiGl1.color.c3fv( @axisX );
// draw debug
     for i := 0 to drawMesh( inData^ ).cntV do
     begin
     apiGl1.vertex.v3fv( @drawMesh( inData^ ).verts[ i ] );
     tmp := ( drawMesh( inData^ ).norm[ i ] ) + drawMesh( inData^ ).verts[ i ];
     apiGl1.vertex.v3fv( @tmp );
     end;
     apiGl1.draw.off;
     end;
///
    drwCube :
     ;
    drwSprite :
     apiGl1.vertex.v3fv( @structSprite( inData^ ).pos );
    drwAxis :
     begin
     exit;
     apiGl1.draw.&on( gllines );
// draw X
     apiGl1.color.c3fv( @axisX );
     apiGl1.vertex.v3fv( @axisX );
// draw X
     apiGl1.color.c3fv( @axisX );
     apiGl1.vertex.v3fv( @nullvec3 );
     apiGl1.vertex.v3fv( @axisX );
// draw Y
     apiGl1.color.c3fv( @axisX );
     apiGl1.vertex.v3fv( @axisX );
// draw Y
     apiGl1.color.c3fv( @axisY );
     apiGl1.vertex.v3fv( @nullvec3 );
     apiGl1.vertex.v3fv( @axisY );
// draw Z
     apiGl1.color.c3fv( @axisZ );
     apiGl1.vertex.v3fv( @nullvec3 );
     apiGl1.vertex.v3fv( @axisZ );
     apiGl1.draw.off;
     end;
  end;
// get gl error
  assert( apiGl1.get.error = 0, 'err' );
end;

// CGL1Api::CGL1Api
procedure CGL1Api.drawEnd;
begin
// swap
  if ( fApi <> nil ) then
    fApi.swap;
end;

{ CGLThread }

// CGLThread::doExecute
procedure CGLThread.doExecute;
var
  glSelf : CGL1Api;
begin
// get class by void
  glSelf := CGL1Api( fData );
// init thread
  glSelf.initThread;
// loop
  while not exit do
  begin
    glSelf.drawRun;
    glSelf.drawCustom( drwAxis, nil );
    INotifier( glSelf.notifier ).doDraw;
    glSelf.drawEnd;
  end;
  glSelf.freeRender;
// call main proc
  inherited;
end;

end.
